package iface.aplicativo.negocio.aps;

import iface.aplicativo.excecao.MensagemException;
import iface.aplicativo.integracao.dao.CategoriaDAO;
import iface.aplicativo.integracao.dao.ContaDAO;
import iface.aplicativo.integracao.dao.EntradaVeiculoDAO;
import iface.aplicativo.integracao.dao.FormaPagamentoDAO;
import iface.aplicativo.integracao.dao.LancamentoDAO;
import iface.aplicativo.integracao.dao.LancamentoItemDAO;
import iface.aplicativo.integracao.dao.PessoaDAO;
import iface.aplicativo.integracao.dao.VeiculoDAO;
import iface.aplicativo.integracao.dao.VendaVeiculoDAO;
import iface.aplicativo.negocio.entidade.Categoria;
import iface.aplicativo.negocio.entidade.Conta;
import iface.aplicativo.negocio.entidade.EntradaVeiculo;
import iface.aplicativo.negocio.entidade.FormaPagamento;
import iface.aplicativo.negocio.entidade.Lancamento;
import iface.aplicativo.negocio.entidade.LancamentoItem;
import iface.aplicativo.negocio.entidade.Pessoa;
import iface.aplicativo.negocio.entidade.Veiculo;
import iface.aplicativo.negocio.entidade.VendaVeiculo;
import iface.aplicativo.negocio.enumerador.PeriodicidadeEnum;
import iface.aplicativo.negocio.enumerador.TipoLancamentoEnum;
import iface.aplicativo.negocio.enumerador.TipoVinculoLancamentoEnum;
import iface.aplicativo.util.Constantes;
import iface.aplicativo.util.ResourceMessageFactory;
import iface.aplicativo.util.UtilResource;
import iface.arquitetura.utilitario.ListaTO;
import iface.arquitetura.utilitario.ListaUtil;
import iface.arquitetura.utilitario.ResourceMessageAnnotation;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.faces.model.SelectItem;

import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(readOnly = true, rollbackFor = { Exception.class })
public class VenderVeiculosAPS {

	@ResourceMessageAnnotation(propertiesFile = { Constantes.RECURSO_MENSAGENS })
	private UtilResource resource = ResourceMessageFactory.inicialize(this);

	@Resource
	VendaVeiculoDAO vendaVeiculoDAO;
	@Resource
	LancamentoDAO lancamentoDAO;
	@Resource
	EntradaVeiculoDAO entradaVeiculoDAO;
	@Resource
	LancamentoItemDAO lancamentoItemDAO;
	@Resource
	CategoriaDAO categoriaDAO;
	@Resource
	ContaDAO contaDAO;
	@Resource
	FormaPagamentoDAO formaPagamentoDAO;
	@Resource
	PessoaDAO pessoaDAO;
	@Resource
	VeiculoDAO veiculoDAO;

	@Transactional(propagation = Propagation.REQUIRED)
	public String cadastrarVendaVeiculo(VendaVeiculo entidade) throws Exception {
		EntradaVeiculo entrada = null;
		if (entidade.getVeiculo() != null
				&& entidade.getVeiculo().getIdVeiculo() != null) {
			entrada = this.verificarPermissaoCadastro(entidade);
		}
		if (entidade.getVeiculo() != null
				&& entidade.getVeiculo().getValorVenda() != null) {
			entidade.setVlrVenda(entidade.getVeiculo().getValorVenda());
		}
		this.validarCamposLancamento(entidade);

		List<Lancamento> lancamentos = entidade.getLancamentos();
		entidade.setLancamentos(null);

		if (entrada != null) {
			entrada = this.entradaVeiculoDAO.obter(entrada.getId());
			entidade.setEntradaVeiculo(entrada);
		}

		if (entidade.getIdVendaVeiculo() == null) {
			entidade.setDtVenda(new Date());
			this.vendaVeiculoDAO.inserir(entidade);
			if (entrada != null) {
				entrada.setVendaVeiculo(entidade);
				this.entradaVeiculoDAO.alterar(entrada);
			}
			this.salvarItens(entidade, lancamentos);
			return this.resource.getMensagens("MSG01");
		} else {
			entidade.setDtAtualizacao(new Date());
			this.vendaVeiculoDAO.alterar(entidade);
			this.salvarItens(entidade, lancamentos);
			return this.resource.getMensagens("MSG02");
		}

	}

	public EntradaVeiculo verificarPermissaoCadastro(
			final VendaVeiculo vendaVeiculo) throws MensagemException,
			Exception {
		EntradaVeiculo entrada = null;

		if (vendaVeiculo.getIdVendaVeiculo() != null) {
			VendaVeiculo vendaVeiculoAux = this.vendaVeiculoDAO
					.obter(vendaVeiculo.getIdVendaVeiculo());
			this.vendaVeiculoDAO.getHibernateTemplate().clear();
			if (vendaVeiculoAux.getVeiculo().getIdVeiculo()
					.equals(vendaVeiculoAux.getVeiculo().getIdVeiculo())) {
				return entrada;
			}
		}

		Collection<EntradaVeiculo> entradas = this.entradaVeiculoDAO
				.consultarEntradaPorVeiculo(vendaVeiculo.getVeiculo());

		if (entradas == null || entradas.isEmpty()) {
			throw new MensagemException(this.resource.getMensagens("MSG023"));
		} else {
			entrada = entradas.iterator().next();
			if (entrada.getVendaVeiculo() != null) {
				throw new MensagemException(
						this.resource.getMensagens("MSG024"));
			}
		}

		return entrada;
	}

	public void salvarItens(VendaVeiculo entidade, List<Lancamento> lancamentos)
			throws Exception {
		Collection<Lancamento> lancamentosSync = this.lancamentoDAO
				.consultarLancamentosPorVendaVeiculoId(entidade
						.getIdVendaVeiculo());

		if (lancamentosSync != null && !lancamentosSync.isEmpty()) {
			for (Lancamento lancamento : lancamentosSync) {
				if (!lancamentos.contains(lancamento)) {
					this.lancamentoDAO.remover(lancamento);
				}
			}

			this.lancamentoDAO.getHibernateTemplate().clear();

			for (Lancamento lancamento : lancamentos) {
				Lancamento lancamentoTemp = new Lancamento();
				PropertyUtils.copyProperties(lancamentoTemp, lancamento);
				lancamentoTemp.setVendaVeiculo(entidade);

				List<LancamentoItem> itens = lancamentoTemp
						.getLancamentoItems();
				lancamentoTemp.setLancamentoItems(null);
				this.lancamentoDAO.salvar(lancamentoTemp);

				for (LancamentoItem lancamentoItem : itens) {
					lancamentoItem.setLancamento(lancamentoTemp);
					this.lancamentoItemDAO.salvar(lancamentoItem);
				}
			}
		} else if (lancamentos != null && !lancamentos.isEmpty()) {
			for (Lancamento lancamento : lancamentos) {
				Lancamento lancamentoTemp = new Lancamento();
				PropertyUtils.copyProperties(lancamentoTemp, lancamento);
				lancamentoTemp.setVendaVeiculo(entidade);

				List<LancamentoItem> itens = lancamentoTemp
						.getLancamentoItems();
				lancamentoTemp.setLancamentoItems(null);
				this.lancamentoDAO.inserir(lancamentoTemp);

				for (LancamentoItem lancamentoItem : itens) {
					lancamentoItem.setLancamento(lancamentoTemp);
					this.lancamentoItemDAO.inserir(lancamentoItem);
				}
			}
		}
	}

	public void validarCamposLancamento(VendaVeiculo entidade) throws Exception {
		this.resource.clearMensagens();

		if (entidade != null) {
			if (entidade.getVeiculo() == null
					|| entidade.getVeiculo().getIdVeiculo() == null) {
				this.resource.addMensagens("MSG05", "Placa");
			}
			if (entidade.getVlrVenda() == null) {
				this.resource.addMensagens("MSG05", "Valor de venda");
			}
			if (entidade.getCliente() == null
					|| entidade.getCliente().getIdPessoa() == null) {
				this.resource.addMensagens("MSG05", "Cliente");
			}
		}

		if (this.resource.isMensagens()) {
			throw new MensagemException(this.resource.getMensagens());
		}
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public String excluirVenda(VendaVeiculo entidade) throws Exception {
		try {
			EntradaVeiculo entrada = this.entradaVeiculoDAO.obter(entidade
					.getEntradaVeiculo().getId());
			entrada.setVendaVeiculo(null);
			this.entradaVeiculoDAO.alterar(entrada);

			this.entradaVeiculoDAO.getHibernateTemplate().clear();

			this.vendaVeiculoDAO.remover(entidade);
		} catch (Exception ex) {
			throw new Exception(ex);
		}
		return this.resource.getMensagens("MSG03");
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public String excluirLancamentoItem(LancamentoItem entidade)
			throws Exception {
		try {
			this.lancamentoItemDAO.remover(entidade);
		} catch (Exception ex) {
			throw new Exception(ex);
		}
		return this.resource.getMensagens("MSG03");
	}

	public Collection<EntradaVeiculo> consultarEntradaPorVeiculo(
			final Veiculo veiculo) {
		return this.entradaVeiculoDAO.consultarEntradaPorVeiculo(veiculo);
	}

	public Collection<VendaVeiculo> consultarTodasVendasVeiculos() {
		Collection<VendaVeiculo> vendas = this.vendaVeiculoDAO.consultar();
		for (VendaVeiculo venda : vendas) {
			for (Lancamento lancamento : venda.getLancamentos()) {
				lancamento.getLancamentoItems().size();
			}
		}
		return vendas;
	}

	public Collection<ListaTO> consultarTodasCategorias() {
		final List<ListaTO> lista = ListaUtil.listaBean2Lista(
				this.categoriaDAO.consultar(), "id", "nmCategoria");

		return lista;
	}

	public Collection<ListaTO> consultarTodasContas() {
		Collection<Conta> contas = this.contaDAO.consultar();
		ArrayList<ListaTO> res = null;
		try {
			res = new ArrayList<ListaTO>();
			ListaTO listaTOaux = new ListaTO("", ":: Selecione ::");
			res.add(listaTOaux);
			for (final Conta c : contas) {
				ListaTO to = new ListaTO();
				to.setValue(c.getId().toString());
				to.setLabel(c.getNmBanco() + " :: " + c.getNrAgencia() + " :: "
						+ c.getNrConta());
				res.add(to);
			}
		} catch (final Exception e) {
		}

		return res;
	}

	public Collection<ListaTO> consultarTodasFormasPagamento() {
		final List<ListaTO> lista = ListaUtil.listaBean2Lista(
				this.formaPagamentoDAO.consultar(), "id", "descricao");

		return lista;
	}

	public List<SelectItem> consultarTiposLancamento() {
		List<SelectItem> lista = new ArrayList<SelectItem>();
		lista.add(new SelectItem(TipoLancamentoEnum.P, TipoLancamentoEnum.P
				.getLabel()));
		lista.add(new SelectItem(TipoLancamentoEnum.R, TipoLancamentoEnum.R
				.getLabel()));

		return lista;
	}

	public List<SelectItem> consultarTiposVinculos() {
		List<SelectItem> lista = new ArrayList<SelectItem>();
		lista.add(new SelectItem(TipoVinculoLancamentoEnum.V,
				TipoVinculoLancamentoEnum.V.getLabel()));
		lista.add(new SelectItem(TipoVinculoLancamentoEnum.C,
				TipoVinculoLancamentoEnum.C.getLabel()));
		lista.add(new SelectItem(TipoVinculoLancamentoEnum.O,
				TipoVinculoLancamentoEnum.O.getLabel()));

		return lista;
	}

	public List<SelectItem> consultarPeriodos() {
		List<SelectItem> lista = new ArrayList<SelectItem>();
		lista.add(new SelectItem(PeriodicidadeEnum.D, PeriodicidadeEnum.D
				.getLabel()));
		lista.add(new SelectItem(PeriodicidadeEnum.M, PeriodicidadeEnum.M
				.getLabel()));
		lista.add(new SelectItem(PeriodicidadeEnum.A, PeriodicidadeEnum.A
				.getLabel()));

		return lista;
	}

	public Collection<Pessoa> consultarPessoasPorNome(final String nome) {
		return this.pessoaDAO.consultarFornecedoresPorNome(nome);
	}

	public Collection<Veiculo> consultarVeiculosVendaPorPlaca(
			final String nrPlaca) {
		return this.veiculoDAO.consultarVeiculosVendaPorPlaca(nrPlaca);
	}

	public Categoria consultarCategoriaPorId(Long id) {
		return this.categoriaDAO.obter(id);
	}

	public Conta consultarContaPorId(Long id) {
		return this.contaDAO.obter(id);
	}

	public FormaPagamento consultarFormaPagamentoPorId(Long id) {
		return this.formaPagamentoDAO.obter(id);
	}

}
